home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / minix / libsrc~1.z / libsrc~1 / doprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-12-28  |  17.0 KB  |  727 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19.  * minorly customized for gcc lib
  20.  *    ++jrb
  21.  */
  22.  
  23. #ifdef LIBC_SCCS
  24. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  25. #endif /* LIBC_SCCS */
  26.  
  27. #include <sys/types.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <string.h>
  32. #include <limits.h>
  33. #include <unistd.h>
  34.  
  35. typedef unsigned char u_char;
  36. typedef unsigned long u_long;
  37.  
  38.  
  39. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  40. #define    MAXEXP        308
  41. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  42. #define    MAXFRACT    39
  43.  
  44. #define    DEFPREC        6
  45.  
  46. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  47.  
  48. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  49.  
  50. #define ARG(basetype) \
  51.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  52.         flags&SHORTINT ? (short basetype)va_arg(argp, short) : \
  53.         va_arg(argp, int)
  54.  
  55. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  56.  
  57. #define    todigit(c)    ((c) - '0')
  58. #define    tochar(n)    ((n) + '0')
  59. #ifndef isascii
  60. #include <ansi.h>
  61. _PROTOTYPE(int isascii, (int) );
  62. #define isascii(c)    (((unsigned char)(c)) <= 0177)
  63. #endif
  64.  
  65. #define    LONGINT        0x01        /* long integer */
  66. #define    LONGDBL        0x02        /* long double; unimplemented */
  67. #define    SHORTINT    0x04        /* short integer */
  68. #define    ALT        0x08        /* alternate form */
  69. #define    LADJUST        0x10        /* left adjustment */
  70. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  71. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  72.  
  73. #ifndef __NO_FLOAT__
  74. #define __FLOATS__ 1
  75. #endif
  76.  
  77. #ifdef __FLOATS__
  78. #ifdef __STDC__
  79. static char *exponent(char *, int, int);
  80. static char *round(double, int *, char *, char *, int, char *);
  81. static int  cvt(double, int, int, char *, int, char *, char *);
  82. #else
  83. static char *exponent();
  84. static char *round();
  85. static int  cvt();
  86. #endif
  87. #endif
  88.  
  89. #ifdef __GNUC__
  90. #define _ICONV(NUMBER, BASE, BUF)                 \
  91. {                                \
  92.     short i;                            \
  93.     if(NUMBER <= 65535L)                    \
  94.     {                                \
  95.     do                             \
  96.     {                            \
  97.         __asm__ volatile("  \
  98.          divu    %3,%2;  \
  99.          swap    %0;     \
  100.          movw    %0,%1;  \
  101.          clrw    %0;     \
  102.                 swap    %0"                    \
  103.              : "=d"((long)NUMBER), "=g"(i)            \
  104.          : "0"((long)NUMBER), "g"((short)BASE));    \
  105.         *--BUF = digs[i];                    \
  106.     } while(NUMBER);                    \
  107.     }                                \
  108.     else                            \
  109.     {                                \
  110.     extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */     \
  111.     do                             \
  112.     {                            \
  113.         __asm__ volatile("        \
  114.          movl    %3,sp@-;      \
  115.          movl    %2,sp@-;      \
  116.          jsr    ___udivsi3;    \
  117.          movl    d0,%0;        \
  118.          movw    d1,%1;        \
  119.          addqw    #8,sp"                    \
  120.              : "=g"((long)NUMBER), "=g"(i)            \
  121.          : "0"((long)NUMBER), "g"((long)BASE)        \
  122.              : "d0", "d1", "a0", "a1");            \
  123.         *--BUF = digs[i];                    \
  124.     } while(NUMBER);                    \
  125.     }                                \
  126. }
  127. #endif /* __GNUC__ */
  128.  
  129.  
  130. int _doprnt(fp, fmt0, argp)
  131.     register FILE *fp;
  132.     u_char *fmt0;
  133.     va_list argp;
  134. {
  135.     register u_char *fmt;    /* format string */
  136.     register int ch;    /* character from fmt */
  137.     register int cnt;    /* return value accumulator */
  138.     register int n;        /* random handy integer */
  139.     register char *t;    /* buffer pointer */
  140.     double _double;        /* double precision arguments %[eEfgG] */
  141.     u_long _ulong;        /* integer arguments %[diouxX] */
  142.     short base;        /* base for [diouxX] conversion */
  143.     short dprec;        /* decimal precision in [diouxX] */
  144.     short fieldsz;        /* field size expanded by sign, etc */
  145.     short flags;        /* flags as above */
  146.     short fpprec;        /* `extra' floating precision in [eEfgG] */
  147.     short prec;        /* precision from format (%.3d), or -1 */
  148.     short realsz;        /* field size expanded by decimal precision */
  149.     short size;        /* size of converted field or string */
  150.     short width;        /* width from format (%8d), or 0 */
  151.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  152.     char softsign;        /* temporary negative sign for floats */
  153.     char *digs;        /* digits for [diouxX] conversion */
  154.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  155.  
  156.     fmt = fmt0;
  157.     digs = "0123456789abcdef";
  158.     for (cnt = 0;; ++fmt) {
  159.         if (!(ch = *fmt))
  160.             return (cnt);
  161.         if (ch != '%') {
  162.             PUTC(ch);
  163.             continue;
  164.         }
  165.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  166.         prec = -1;
  167.         sign = '\0';
  168.  
  169. rflag:        switch (*++fmt) {
  170.         case ' ':
  171.             /*
  172.              * ``If the space and + flags both appear, the space
  173.              * flag will be ignored.''
  174.              *    -- ANSI X3J11
  175.              */
  176.             if (!sign)
  177.                 sign = ' ';
  178.             goto rflag;
  179.         case '#':
  180.             flags |= ALT;
  181.             goto rflag;
  182.         case '*':
  183.             /*
  184.              * ``A negative field width argument is taken as a
  185.              * - flag followed by a  positive field width.''
  186.              *    -- ANSI X3J11
  187.              * They don't exclude field widths read from args.
  188.              */
  189.             if ((width = (short)(va_arg(argp, int))) >= 0)
  190.                 goto rflag;
  191.             width = -width;
  192.             /* FALLTHROUGH */
  193.         case '-':
  194.             flags |= LADJUST;
  195.             goto rflag;
  196.         case '+':
  197.             sign = '+';
  198.             goto rflag;
  199.         case '.':
  200.             if (*++fmt == '*')
  201.                 n = va_arg(argp, int);
  202.             else {
  203.                 n = 0;
  204.                 while (isascii(*fmt) && isdigit(*fmt))
  205.                     n = TEN_MUL(n) + todigit(*fmt++);
  206.                 --fmt;
  207.             }
  208.             prec = n < 0 ? -1 : n;
  209.             goto rflag;
  210.         case '0':
  211.             /*
  212.              * ``Note that 0 is taken as a flag, not as the
  213.              * beginning of a field width.''
  214.              *    -- ANSI X3J11
  215.              */
  216.             flags |= ZEROPAD;
  217.             goto rflag;
  218.         case '1': case '2': case '3': case '4':
  219.         case '5': case '6': case '7': case '8': case '9':
  220.             n = 0;
  221.             do {
  222.                 n = TEN_MUL(n) + todigit(*fmt);
  223.             } while (isascii(*++fmt) && isdigit(*fmt));
  224.             width = n;
  225.             --fmt;
  226.             goto rflag;
  227.         case 'L':
  228.             flags |= LONGDBL;
  229.             goto rflag;
  230.         case 'h':
  231.             flags |= SHORTINT;
  232.             goto rflag;
  233.         case 'l':
  234.             flags |= LONGINT;
  235.             goto rflag;
  236.         case 'c':
  237.             *(t = buf) = va_arg(argp, int);
  238.             size = 1;
  239.             sign = '\0';
  240.             goto pforw;
  241.         case 'D':
  242.             flags |= LONGINT;
  243.             /*FALLTHROUGH*/
  244.         case 'd':
  245.         case 'i':
  246.             ARG(int);
  247.             if ((long)_ulong < 0) {
  248.                 _ulong = -_ulong;
  249.                 sign = '-';
  250.             }
  251.             base = 10;
  252.             goto number;
  253. #ifdef __FLOATS__
  254.         case 'e':
  255.         case 'E':
  256.         case 'f':
  257.         case 'g':
  258.         case 'G':
  259.             _double = va_arg(argp, double);
  260.             /*
  261.              * don't do unrealistic precision; just pad it with
  262.              * zeroes later, so buffer size stays rational.
  263.              */
  264.             if (prec > MAXFRACT) {
  265.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  266.                     fpprec = prec - MAXFRACT;
  267.                 prec = MAXFRACT;
  268.             }
  269.             else if (prec == -1)
  270.                 prec = DEFPREC;
  271.             /*
  272.              * softsign avoids negative 0 if _double is < 0 and
  273.              * no significant digits will be shown
  274.              */
  275.             if (_double < 0) {
  276.                 softsign = '-';
  277.                 _double = -_double;
  278.             }
  279.             else
  280.                 softsign = 0;
  281.             /*
  282.              * cvt may have to round up past the "start" of the
  283.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  284.              * if the first char isn't NULL, it did.
  285.              */
  286.             *buf = (char)NULL;
  287.             size = cvt(_double, (int)prec, (int)flags, &softsign,
  288.                    *fmt, buf, buf + (int)sizeof(buf)); 
  289.             if (softsign)
  290.                 sign = '-';
  291.             t = *buf ? buf : buf + 1;
  292.             goto pforw;
  293. #endif /* __FLOATS__ */
  294.         case 'n':
  295.             if (flags & LONGINT)
  296.                 *va_arg(argp, long *) = cnt;
  297.             else if (flags & SHORTINT)
  298.                 *va_arg(argp, short *) = cnt;
  299.             else
  300.                 *va_arg(argp, int *) = cnt;
  301.             break;
  302.         case 'O':
  303.             flags |= LONGINT;
  304.             /*FALLTHROUGH*/
  305.         case 'o':
  306.             ARG(unsigned);
  307.             base = 8;
  308.             goto nosign;
  309.         case 'p':
  310.             /*
  311.              * ``The argument shall be a pointer to void.  The
  312.              * value of the pointer is converted to a sequence
  313.              * of printable characters, in an implementation-
  314.              * defined manner.''
  315.              *    -- ANSI X3J11
  316.              */
  317.             /* NOSTRICT */
  318.             _ulong = (u_long)va_arg(argp, void *);
  319.             base = 16;
  320.             goto nosign;
  321.         case 's':
  322.             if (!(t = va_arg(argp, char *)))
  323.                 t = "(null)";
  324.             if (prec >= 0) {
  325.                 /*
  326.                  * can't use strlen; can only look for the
  327.                  * NUL in the first `prec' characters, and
  328.                  * strlen() will go further.
  329.                  */
  330. #ifdef __GNUC__
  331.                 char *p;
  332.                 void *memchr();
  333. #else
  334.                 char *p, *memchr();
  335. #endif
  336.  
  337.                 if (p = (char *)memchr(t, 0, (size_t)prec)) {
  338.                     size = p - t;
  339.                     if (size > prec)
  340.                         size = prec;
  341.                 } else
  342.                     size = prec;
  343.             } else
  344.                 size = (int)strlen(t);
  345.             sign = '\0';
  346.             goto pforw;
  347.         case 'U':
  348.             flags |= LONGINT;
  349.             /*FALLTHROUGH*/
  350.         case 'u':
  351.             ARG(unsigned);
  352.             base = 10;
  353.             goto nosign;
  354.         case 'X':
  355.             digs = "0123456789ABCDEF";
  356.             /* FALLTHROUGH */
  357.         case 'x':
  358.             ARG(unsigned);
  359.             base = 16;
  360.             /* leading 0x/X only if non-zero */
  361.             if (flags & ALT && _ulong != 0)
  362.                 flags |= HEXPREFIX;
  363.  
  364.             /* unsigned conversions */
  365. nosign:            sign = '\0';
  366.             /*
  367.              * ``... diouXx conversions ... if a precision is
  368.              * specified, the 0 flag will be ignored.''
  369.              *    -- ANSI X3J11
  370.              */
  371. number:            if ((dprec = prec) >= 0)
  372.                 flags &= ~ZEROPAD;
  373.  
  374.             /*
  375.              * ``The result of converting a zero value with an
  376.              * explicit precision of zero is no characters.''
  377.              *    -- ANSI X3J11
  378.              */
  379.             t = buf + BUF;
  380.             if (_ulong != 0 || prec != 0) {
  381. #ifndef __GNUC__
  382.                 do {
  383.                     *--t = digs[_ulong % base];
  384.                     _ulong /= base;
  385.                 } while (_ulong);
  386. #else
  387.                 _ICONV(_ulong, base, t);
  388. #endif                
  389.                 digs = "0123456789abcdef";
  390.                 if (flags & ALT && base == 8 && *t != '0')
  391.                     *--t = '0'; /* octal leading 0 */
  392.             }
  393.             size = buf + BUF - t;
  394.  
  395. pforw:
  396.             /*
  397.              * All reasonable formats wind up here.  At this point,
  398.              * `t' points to a string which (if not flags&LADJUST)
  399.              * should be padded out to `width' places.  If
  400.              * flags&ZEROPAD, it should first be prefixed by any
  401.              * sign or other prefix; otherwise, it should be blank
  402.              * padded before the prefix is emitted.  After any
  403.              * left-hand padding and prefixing, emit zeroes
  404.              * required by a decimal [diouxX] precision, then print
  405.              * the string proper, then emit zeroes required by any
  406.              * leftover floating precision; finally, if LADJUST,
  407.              * pad with blanks.
  408.              */
  409.  
  410.             /*
  411.              * compute actual size, so we know how much to pad
  412.              * fieldsz excludes decimal prec; realsz includes it
  413.              */
  414.             fieldsz = size + fpprec;
  415.             if (sign)
  416.                 fieldsz++;
  417.             if (flags & HEXPREFIX)
  418.                 fieldsz += 2;
  419.             realsz = dprec > fieldsz ? dprec : fieldsz;
  420.  
  421.             /* right-adjusting blank padding */
  422.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  423.                 for (n = realsz; n < width; n++)
  424.                     PUTC(' ');
  425.             /* prefix */
  426.             if (sign)
  427.                 PUTC(sign);
  428.             if (flags & HEXPREFIX) {
  429.                 PUTC('0');
  430.                 PUTC((char)*fmt);
  431.             }
  432.             /* right-adjusting zero padding */
  433.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  434.                 for (n = realsz; n < width; n++)
  435.                     PUTC('0');
  436.             /* leading zeroes from decimal precision */
  437.             for (n = fieldsz; n < dprec; n++)
  438.                 PUTC('0');
  439.  
  440.             /* the string or number proper */
  441.             for (n = size; --n >= 0; )
  442.                 PUTC(*t++);
  443.             /* trailing f.p. zeroes */
  444.             while (--fpprec >= 0)
  445.                 PUTC('0');
  446.             /* left-adjusting padding (always blank) */
  447.             if (flags & LADJUST)
  448.                 for (n = realsz; n < width; n++)
  449.                     PUTC(' ');
  450.             /* finally, adjust cnt */
  451.             cnt += width > realsz ? width : realsz;
  452.             break;
  453.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  454.             return (cnt);
  455.         default:
  456.             PUTC((char)*fmt);
  457.             cnt++;
  458.         }
  459.     }
  460.     /* NOTREACHED */
  461. }
  462.  
  463. #ifdef __FLOATS__
  464. static int
  465. cvt(number,prec,flags, signp, fmtch, startp, endp)
  466.     double number;
  467.     register int prec;
  468.     int flags;
  469.     int fmtch;
  470.     char *signp, *startp, *endp;
  471. {
  472.     register char *p, *t;
  473.     register double fract;
  474.     int dotrim, expcnt, gformat;
  475.     double integer, tmp, modf();
  476.     char *exponent(), *round();
  477.  
  478.     dotrim = expcnt = gformat = 0;
  479.     fract = modf(number, &integer);
  480.  
  481.     /* get an extra slot for rounding. */
  482.     t = ++startp;
  483.  
  484.     /*
  485.      * get integer portion of number; put into the end of the buffer; the
  486.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  487.      */
  488.     for (p = endp - 1; integer; ++expcnt) {
  489.         tmp = modf(integer / 10, &integer);
  490.         *p-- = tochar((int)((tmp + .01) * 10));
  491.     }
  492.     switch(fmtch) {
  493.     case 'f':
  494.         /* reverse integer into beginning of buffer */
  495.         if (expcnt)
  496.             for (; ++p < endp; *t++ = *p);
  497.         else
  498.             *t++ = '0';
  499.         /*
  500.          * if precision required or alternate flag set, add in a
  501.          * decimal point.
  502.          */
  503.         if (prec || flags&ALT)
  504.             *t++ = '.';
  505.         /* if requires more precision and some fraction left */
  506.         if (fract) {
  507.             if (prec)
  508.                 do {
  509.                     fract = modf(fract * 10, &tmp);
  510.                     *t++ = tochar((int)tmp);
  511.                 } while (--prec && fract);
  512.             if (fract)
  513.                 startp = round(fract, (int *)NULL, startp,
  514.                     t - 1, (char)0, signp);
  515.         }
  516.         for (; prec--; *t++ = '0');
  517.         break;
  518.     case 'e':
  519.     case 'E':
  520. eformat:    if (expcnt) {
  521.             *t++ = *++p;
  522.             if (prec || flags&ALT)
  523.                 *t++ = '.';
  524.             /* if requires more precision and some integer left */
  525.             for (; prec && ++p < endp; --prec)
  526.                 *t++ = *p;
  527.             /*
  528.              * if done precision and more of the integer component,
  529.              * round using it; adjust fract so we don't re-round
  530.              * later.
  531.              */
  532.             if (!prec && ++p < endp) {
  533.                 fract = 0;
  534.                 startp = round((double)0, &expcnt, startp,
  535.                     t - 1, *p, signp);
  536.             }
  537.             /* adjust expcnt for digit in front of decimal */
  538.             --expcnt;
  539.         }
  540.         /* until first fractional digit, decrement exponent */
  541.         else if (fract) {
  542.             /* adjust expcnt for digit in front of decimal */
  543.             for (expcnt = -1;; --expcnt) {
  544.                 fract = modf(fract * 10, &tmp);
  545.                 if (tmp)
  546.                     break;
  547.             }
  548.             *t++ = tochar((int)tmp);
  549.             if (prec || flags&ALT)
  550.                 *t++ = '.';
  551.         }
  552.         else {
  553.             *t++ = '0';
  554.             if (prec || flags&ALT)
  555.                 *t++ = '.';
  556.         }
  557.         /* if requires more precision and some fraction left */
  558.         if (fract) {
  559.             if (prec)
  560.                 do {
  561.                     fract = modf(fract * 10, &tmp);
  562.                     *t++ = tochar((int)tmp);
  563.                 } while (--prec && fract);
  564.             if (fract)
  565.                 startp = round(fract, &expcnt, startp,
  566.                     t - 1, (char)0, signp);
  567.         }
  568.         /* if requires more precision */
  569.         for (; prec--; *t++ = '0');
  570.  
  571.         /* unless alternate flag, trim any g/G format trailing 0's */
  572.         if (gformat && !(flags&ALT)) {
  573.             while (t > startp && *--t == '0');
  574.             if (*t == '.')
  575.                 --t;
  576.             ++t;
  577.         }
  578.         t = exponent(t, expcnt, fmtch);
  579.         break;
  580.     case 'g':
  581.     case 'G':
  582.         /* a precision of 0 is treated as a precision of 1. */
  583.         if (!prec)
  584.             ++prec;
  585.         /*
  586.          * ``The style used depends on the value converted; style e
  587.          * will be used only if the exponent resulting from the
  588.          * conversion is less than -4 or greater than the precision.''
  589.          *    -- ANSI X3J11
  590.          */
  591.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  592.             /*
  593.              * g/G format counts "significant digits, not digits of
  594.              * precision; for the e/E format, this just causes an
  595.              * off-by-one problem, i.e. g/G considers the digit
  596.              * before the decimal point significant and e/E doesn't
  597.              * count it as precision.
  598.              */
  599.             --prec;
  600.             fmtch -= 2;        /* G->E, g->e */
  601.             gformat = 1;
  602.             goto eformat;
  603.         }
  604.         /*
  605.          * reverse integer into beginning of buffer,
  606.          * note, decrement precision
  607.          */
  608.         if (expcnt)
  609.             for (; ++p < endp; *t++ = *p, --prec);
  610.         else
  611.             *t++ = '0';
  612.         /*
  613.          * if precision required or alternate flag set, add in a
  614.          * decimal point.  If no digits yet, add in leading 0.
  615.          */
  616.         if (prec || flags&ALT) {
  617.             dotrim = 1;
  618.             *t++ = '.';
  619.         }
  620.         else
  621.             dotrim = 0;
  622.         /* if requires more precision and some fraction left */
  623.         if (fract) {
  624.             if (prec) {
  625.                 do {
  626.                     fract = modf(fract * 10, &tmp);
  627.                     *t++ = tochar((int)tmp);
  628.                 } while(!tmp);
  629.                 while (--prec && fract) {
  630.                     fract = modf(fract * 10, &tmp);
  631.                     *t++ = tochar((int)tmp);
  632.                 }
  633.             }
  634.             if (fract)
  635.                 startp = round(fract, (int *)NULL, startp,
  636.                     t - 1, (char)0, signp);
  637.         }
  638.         /* alternate format, adds 0's for precision, else trim 0's */
  639.         if (flags&ALT)
  640.             for (; prec--; *t++ = '0');
  641.         else if (dotrim) {
  642.             while (t > startp && *--t == '0');
  643.             if (*t != '.')
  644.                 ++t;
  645.         }
  646.     }
  647.     return((int)(t - startp));
  648. }
  649.  
  650. static char *
  651. round(fract, exp, start, end, ch, signp)
  652.     double fract;
  653.     int *exp;
  654.     register char *start, *end;
  655.     int ch;
  656.     char *signp;
  657. {
  658.     double tmp;
  659.  
  660.     if (fract)
  661.         (void)modf(fract * 10, &tmp);
  662.     else
  663.         tmp = todigit(ch);
  664.     if (tmp > 4)
  665.         for (;; --end) {
  666.             if (*end == '.')
  667.                 --end;
  668.             if (++*end <= '9')
  669.                 break;
  670.             *end = '0';
  671.             if (end == start) {
  672.                 if (exp) {    /* e/E; increment exponent */
  673.                     *end = '1';
  674.                     ++*exp;
  675.                 }
  676.                 else {        /* f; add extra digit */
  677.                     *--end = '1';
  678.                     --start;
  679.                 }
  680.                 break;
  681.             }
  682.         }
  683.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  684.     else if (*signp == '-')
  685.         for (;; --end) {
  686.             if (*end == '.')
  687.                 --end;
  688.             if (*end != '0')
  689.                 break;
  690.             if (end == start)
  691.                 *signp = 0;
  692.         }
  693.     return(start);
  694. }
  695.  
  696. static char *
  697. exponent(p, exp, fmtch)
  698.     register char *p;
  699.     register int exp;
  700.     int fmtch;
  701. {
  702.     register char *t;
  703.     char expbuf[MAXEXP];
  704.  
  705.     *p++ = fmtch;
  706.     if (exp < 0) {
  707.         exp = -exp;
  708.         *p++ = '-';
  709.     }
  710.     else
  711.         *p++ = '+';
  712.     t = expbuf + MAXEXP;
  713.     if (exp > 9) {
  714.         do {
  715.             *--t = tochar(exp % 10);
  716.         } while ((exp /= 10) > 9);
  717.         *--t = tochar(exp);
  718.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  719.     }
  720.     else {
  721.         *p++ = '0';
  722.         *p++ = tochar(exp);
  723.     }
  724.     return(p);
  725. }
  726. #endif __FLOATS__
  727.